﻿using System;
using System.ComponentModel;
#if NETFX_CORE
using System.Reflection;
using Windows.UI.Xaml.Controls;
#else
#if SILVERLIGHT
using System.Windows.Controls;
#else
using System.Windows;
#endif
#endif

namespace FreshMeat.Xaml
{
   /// <summary>
   /// Provides simple methods for working with modal dialogs with support for <see cref="IEditableObject"/> 
   /// which can be implemented by the data context (view model) so that when the dialog is accepted the
   /// changes are committed and if the dialog is cancelled then any changes are undone.  All of this can
   /// be accomplished purely from XAML through the use of <see cref="OpenWindowBehavior"/> and 
   /// <see cref="CloseWindowBehavior"/>, both of which leverage this class to manage the dialog.
   /// </summary>
   public static class Dialog
   {
#if NETFX_CORE
      /// <summary>
      /// Creates an instance of a window type and shows it as a modal dialog.
      /// </summary>
      /// <param name="type">Type of window (must be derived from <see cref="Control"/>).</param>
      /// <param name="dataContext">Data context for the window.</param>
      public static void ShowModal(Type type, object dataContext)
      {
         ShowModal(CreateInstance<Control>(type), dataContext);
      }
#elif SILVERLIGHT
      /// <summary>
      /// Creates an instance of a window type and shows it as a modal dialog.
      /// </summary>
      /// <param name="type">Type of window (must be derived from <see cref="ChildWindow"/>).</param>
      /// <param name="dataContext">Data context for the window.</param>
      public static void ShowModal(Type type, object dataContext)
      {
         ShowModal(CreateInstance<ChildWindow>(type), dataContext);
      }
#else
      /// <summary>
      /// Creates an instance of a window type and shows it as a modal dialog.
      /// </summary>
      /// <param name="type">Type of window (must be derived from <see cref="Window"/>).</param>
      /// <param name="dataContext">Data context for the window.</param>
      /// <param name="ownerWindow">Root window.</param>
      public static void ShowModal(Type type, object dataContext, Window ownerWindow)
      {
         ShowModal(CreateInstance<Window>(type), dataContext, ownerWindow);
      }
#endif

      static T CreateInstance<T>(Type type)
      {
#if NETFX_CORE
         if (typeof(T).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
#else
         if (!type.IsSubclassOf(typeof(T)))
#endif
            throw new InvalidOperationException(string.Format("Window type {0} is not derived from {1}.", type.Name, typeof(T).Name));

         var window = (T)Activator.CreateInstance(type);
         return window;
      }

#if NETFX_CORE
      /// <summary>
      /// Shows a window as a modal dialog.
      /// </summary>
      /// <param name="window">The window to show.</param>
      /// <param name="dataContext">The data context for the window; if implemented, <see cref="IEditableObject.BeginEdit"/> is called.</param>
      public static void ShowModal(Control window, object dataContext)
#elif SILVERLIGHT
      /// <summary>
      /// Shows a window as a modal dialog.
      /// </summary>
      /// <param name="window">The window to show.</param>
      /// <param name="dataContext">The data context for the window; if implemented, <see cref="IEditableObject.BeginEdit"/> is called.</param>
      public static void ShowModal(ChildWindow window, object dataContext)
#else
      /// <summary>
      /// Shows a window as a modal dialog.
      /// </summary>
      /// <param name="window">The window to show.</param>
      /// <param name="dataContext">The data context for the window; if implemented, <see cref="IEditableObject.BeginEdit"/> is called.</param>
      /// <param name="owner">The window that owns this window.</param>
      public static void ShowModal(Window window, object dataContext, Window owner)
#endif
      {
         // Reset focus helper since we're changing its whole world by opening a new window
         FocusHelper.Reset();

         window.DataContext = dataContext;

         var editableObject = window.DataContext as IEditableObject;
         if (editableObject != null)
            editableObject.BeginEdit();

#if NETFX_CORE
         throw new InvalidOperationException(); // TODO: Figure out how to show modal dialog for NETFX_CORE
#else
         window.Closed += (sender, args) =>
         {
            if (editableObject != null)
            {
               if (window.DialogResult.GetValueOrDefault())
                  editableObject.EndEdit();
               else
                  editableObject.CancelEdit();
            }

            // Reset focus helper since we're changing its whole world by closing this window
            FocusHelper.Reset();
         };

#if SILVERLIGHT
         window.Show();
#else
         if (owner != null)
            window.Owner = owner;
         else
            System.Diagnostics.Trace.TraceWarning("XChildWindow: Now owner window was specified.");

         window.ShowDialog();
#endif
#endif
      }
   }
}
